home *** CD-ROM | disk | FTP | other *** search
Wrap
/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Forecastfox. * * The Initial Developer of the Original Code is * Jon Stritar <jstritar@MIT.EDU>. * Portions created by the Initial Developer are Copyright (C) 2005 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Jon Stritar <jstritar@MIT.EDU> * Richard Klein <richwklein@mchsi.com> * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ const CLASS_ID = Components.ID("{E39B9B47-0B40-4b61-958E-EA509AA2DF5C}"); const CLASS_NAME = "Forecastfox Disk I/O"; const CONTRACT_ID = "@ensolis.com/forecastfox/disk;1"; const ffIDisk = Components.interfaces.ffIDisk; const nsIFile = Components.interfaces.nsIFile; /****************************************************************************** * ffDisk component ******************************************************************************/ function ffDisk() {}; ffDisk.prototype = { _cache: null, _icons: null, _temp: null, _defaults: null, _transforms: null, _weatherfox: null, _errors: null, _foStream: null, _fiStream: null, _siStream: null, _serializer: null, _parser: null, start: function() { var dirs = Components.classes["@mozilla.org/file/directory_service;1"].getService(Components.interfaces.nsIProperties); var app = dirs.get("XCurProcD", Components.interfaces.nsIFile); var profile = dirs.get("ProfD", Components.interfaces.nsIFile); var install; //get temp directory this._temp = dirs.get("TmpD", Components.interfaces.nsIFile); //use extension manager to figure out install location try { var em = Components.classes["@mozilla.org/extensions/manager;1"].getService(Components.interfaces.nsIExtensionManager); install = em.getItemLocation("{0538E3E3-7E9B-4d49-8831-A227C80A7AD3}"); } catch (e) { install = profile.clone(); install.append("extensions"); install.append("{0538E3E3-7E9B-4d49-8831-A227C80A7AD3}"); if (!install.exists()) { install = this._app.clone(); install.append("extensions"); install.append("{0538E3E3-7E9B-4d49-8831-A227C80A7AD3}"); }; }; //get default and transform locations this._defaults = install.clone(); this._defaults.append("defaults"); this._transforms = this._defaults.clone(); this._transforms.append("transforms"); //get our cache directory this._cache = this._ensureDirectory(profile, "forecastfox"); //get errors directory this._errors = this._ensureDirectory(this._cache, "errors"); //get our icons directory this._icons = this._ensureDirectory(this._cache, "icons"); //get weatherfox directory this._weatherfox = profile.clone(); this._weatherfox.append("weatherfox"); //setup stream components this._foStream = Components.classes["@mozilla.org/network/file-output-stream;1"].createInstance(Components.interfaces.nsIFileOutputStream); this._fiStream = Components.classes["@mozilla.org/network/file-input-stream;1"].createInstance(Components.interfaces.nsIFileInputStream); this._siStream = Components.classes["@mozilla.org/scriptableinputstream;1"].createInstance(Components.interfaces.nsIScriptableInputStream); this._serializer = Components.classes["@mozilla.org/xmlextras/xmlserializer;1"].createInstance(Components.interfaces.nsIDOMSerializer); this._parser = Components.classes["@mozilla.org/xmlextras/domparser;1"].createInstance(Components.interfaces.nsIDOMParser); }, stop: function() { this._cache = null; this._icons = null; this._temp = null; this._defaults = null; this._transforms = null; this._weatherfox = null; this._foStream = null; this._fiStream = null; this._siStream = null; this._serializer = null; this._parser = null; this._errors = null; }, get: function(aName, aType) { var file = null; switch (aType) { case ffIDisk.TYPE_CACHE: default: file = this._cache.clone(); break; case ffIDisk.TYPE_ICONS: file = this._icons.clone(); break; case ffIDisk.TYPE_TEMP: file = this._temp.clone(); break; case ffIDisk.TYPE_WEATHERFOX: file = this._weatherfox.clone(); break; case ffIDisk.TYPE_DEFAULTS: file = this._defaults.clone(); break; case ffIDisk.TYPE_TRANSFORMS: file = this._transforms.clone(); break; case ffIDisk.TYPE_ERRORS: file = this._errors.clone(); }; file.append(aName); if (aType == ffIDisk.TYPE_TEMP) file.createUnique(nsIFile.NORMAL_FILE_TYPE, 0664); return file; }, move: function(aFrom, aTo) { // first move to a unique name var temp = this.get(aTo.leafName, ffIDisk.TYPE_TEMP); aFrom.moveTo(temp.parent, temp.leafName); // now move to the new name temp.moveTo(aTo.parent, aTo.leafName); }, copy: function(aFrom, aTo) { //remove to file if (aTo.exists()) aTo.remove(false); //copy from file aFrom.copyTo(aTo.parent, aTo.leafName); }, getFileURI: function(aFile) { var ios = Components.classes["@mozilla.org/network/io-service;1"].createInstance(Components.interfaces.nsIIOService); var uri = ios.newFileURI(aFile); return uri.spec; }, recordFile: function(aFile) { var file = this.get("", ffIDisk.TYPE_ERRORS); var name = aFile.leafName; if (name.indexOf(".") == -1) name = name + "-err"; else { var ind = name.indexOf("."); var ext = name.substring(ind, name.length); name = name.substring(0, ind); name = name + "-err" + ext; } file.append(name); file.createUnique(nsIFile.NORMAL_FILE_TYPE, 0664); this.copy(aFile, file); //log the error this.recordMessage("Message: Error file (" + file.leafName + ") created for "+aFile.leafName+"."); }, recordMessage: function(aMessage) { // get the error log file var file = this.get("errors.log", ffIDisk.TYPE_ERRORS); // append the new log entry var msg = new Date() + ": " + aMessage + "\r\n"; this._writeString(file, msg, true); }, recordError: function(aMessage, aError) { //write message this.recordMessage(aMessage); //write error this.recordMessage("Exception: " + aError.toString()); //write call stack var frame = aError.location; while (frame) { this.recordMessage("Stack: " + frame.toString()); frame = frame.caller; }; }, clear: function(aType, aCache) { //just get a folder var folder = this.get("", aType); if (!folder.exists()) return; //make sure its a directory if (!folder.isDirectory()) return; //get list of files var entries = folder.directoryEntries; while (entries.hasMoreElements()) { var entry = entries.getNext(); entry = entry.QueryInterface(Components.interfaces.nsIFile); var name = entry.leafName; if (aCache) { //remove cache files if (name.indexOf("cache") != -1) { if (entry.isDirectory()) entry.remove(true); else entry.remove(false); }; } else { //remove all files if (entry.isDirectory()) entry.remove(true); else entry.remove(false); }; } }, remove: function(aType) { //just get a folder var folder = this.get("", aType); if (!folder.exists()) return; //make sure its a directory if (!folder.isDirectory()) return; folder.remove(true); }, read: function(aFile) { //load document into string variable var charset = "UTF-8"; var contents = new String(); this._fiStream.init(aFile, 1, 0, false); try { var is = Components.classes["@mozilla.org/intl/converter-input-stream;1"].createInstance(Components.interfaces.nsIConverterInputStream); is.init(this._fiStream, charset, 1024, Components.interfaces.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER); var str = {}; while (is.readString(this._fiStream.available(), str) != 0) { contents += str.value; }; } catch(e) { var converter = Components.classes["@mozilla.org/intl/scriptableunicodeconverter"].createInstance(Components.interfaces.nsIScriptableUnicodeConverter); converter.charset = charset; this._siStream.init(this._fiStream); while (this._siStream.available() > 0) { var chunk = this._siStream.read(this._siStream.available()); contents += converter.ConvertToUnicode(chunk); }; this._siStream.close(); }; //close file this._fiStream.close(); //convert string to DOM // XXX watch for strange window errors here when modal windows popup on startup var doc = this._parser.parseFromString(contents, "text/xml"); return doc; }, write: function(aDoc, aFile, aBackup) { //create a temporary file var temp = null; if (aFile.parent != this._temp) temp = this.get(aFile.leafName, ffIDisk.TYPE_TEMP); else temp = aFile; //convert the document to a string var content = this._serializer.serializeToString(aDoc); //initialize file stream var flags = 0x02 | 0x08 | 0x20; var charset = "UTF-8"; var os = null; this._foStream.init(temp, flags, 0664, 0); try { //try converter stream os = Components.classes["@mozilla.org/intl/converter-output-stream;1"].createInstance(Components.interfaces.nsIConverterOutputStream); os.init(this._foStream, charset, 0, Components.interfaces.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER); os.writeString(content); os.close; } catch(e) { //use string converter var converter = Components.classes["@mozilla.org/intl/scriptableunicodeconverter"].createInstance(Components.interfaces.nsIScriptableUnicodeConverter); converter.charset = charset; var chunk = converter.ConvertFromUnicode(content); this._foStream.write(chunk, chunk.length); var fin = converter.Finish(); if (fin.length > 0) this._foStream.write(fin, fin.length); }; //close file stream this._foStream.close(); //create a backup if (aBackup) { var name = aFile.leafName; var ext = name.substring(name.lastIndexOf(".") + 1, name.length); name = name.replace(ext, "bak"); var backup = aFile.parent.clone(); backup.append(name); this.copy(temp, backup); }; //move temp to correct location if (aFile.parent != this._temp) this.move(temp, aFile); }, valid: function(aDoc) { //object passed if(!aDoc) return false; //parser error if (aDoc.childNodes[0].localName == "parsererror") return false; return true; }, _ensureDirectory: function(aParent, aName) { var file = aParent.clone(); file.append(aName); if (!file.exists()) file.create(file.DIRECTORY_TYPE, 0755); if (!file.isDirectory()) { file.remove(false); file.create(file.DIRECTORY_TYPE, 0755); }; //make sure we can read and write to and from the directory if (!file.isReadable() || !file.isWritable()) file.permissions = 0755; return file; }, _writeString: function(aFile, aString, aAppend) { //load document into string variable var charset = "UTF-8"; var contents = new String(); var converter = Components.classes["@mozilla.org/intl/scriptableunicodeconverter"].createInstance(Components.interfaces.nsIScriptableUnicodeConverter); converter.charset = charset; // if we're appending, read in the old stuff if (aAppend && aFile.exists() && aFile.isReadable()) { //load document into string variable this._fiStream.init(aFile, 1, 0, false); try { var is = Components.classes["@mozilla.org/intl/converter-input-stream;1"].createInstance(Components.interfaces.nsIConverterInputStream); is.init(this._fiStream, charset, 1024, Components.interfaces.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER); var str = {}; while (is.readString(this._fiStream.available(), str) != 0) { contents += str.value; }; } catch(e) { this._siStream.init(this._fiStream); while (this._siStream.available() > 0) { var chunk = this._siStream.read(this._siStream.available()); contents += converter.ConvertToUnicode(chunk); }; this._siStream.close(); }; //close file this._fiStream.close(); }; contents = contents + converter.ConvertToUnicode(aString); //initialize file stream var flags = 0x02 | 0x08 | 0x20; var os = null; this._foStream.init(aFile, flags, 0664, 0); try { //try converter stream os = Components.classes["@mozilla.org/intl/converter-output-stream;1"].createInstance(Components.interfaces.nsIConverterOutputStream); os.init(this._foStream, charset, 0, Components.interfaces.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER); os.writeString(contents); os.close; } catch(e) { //use string converter var chunk = converter.ConvertFromUnicode(contents); this._foStream.write(chunk, chunk.length); var fin = converter.Finish(); if (fin.length > 0) this._foStream.write(fin, fin.length); }; //close file stream this._foStream.close(); }, /////////////////////////// // nsIClassInfo getInterfaces: function(aCount) { var ifaces = new Array(); ifaces.push(Components.interfaces.ffIDisk); ifaces.push(Components.interfaces.nsIClassInfo); ifaces.push(Components.interfaces.nsISupports); aCount.value = ifaces.length; return ifaces; }, getHelperForLanguage: function(aLanguage) { return null; }, get contractID() { return CONTRACT_ID; }, get classID() { return CLASS_ID; }, get classDescription() { return CLASS_NAME; }, get implementationLanguage() { return Components.interfaces.nsIProgrammingLanguage.JAVASCRIPT; }, get flags() { return Components.interfaces.nsIClassInfo.SINGLETON; }, /////////////////////////// // nsISupports QueryInterface: function (aIID) { if (!aIID.equals(Components.interfaces.ffIDisk) && !aIID.equals(Components.interfaces.nsIClassInfo) && !aIID.equals(Components.interfaces.nsISupports)) throw Components.results.NS_ERROR_NO_INTERFACE; return this; } } /****************************************************************************** * XPCOM Functions for construction and registration ******************************************************************************/ var gModule = { _firstTime: true, registerSelf: function(aCompMgr, aFileSpec, aLocation, aType) { if (this._firstTime) { this._firstTime = false; throw Components.results.NS_ERROR_FACTORY_REGISTER_AGAIN; }; aCompMgr = aCompMgr.QueryInterface(Components.interfaces.nsIComponentRegistrar); aCompMgr.registerFactoryLocation(CLASS_ID, CLASS_NAME, CONTRACT_ID, aFileSpec, aLocation, aType); }, unregisterSelf: function(aCompMgr, aLocation, aType) { aCompMgr = aCompMgr.QueryInterface(Components.interfaces.nsIComponentRegistrar); aCompMgr.unregisterFactoryLocation(CLASS_ID, aLocation); }, getClassObject: function(aCompMgr, aCID, aIID) { if (!aIID.equals(Components.interfaces.nsIFactory)) throw Components.results.NS_ERROR_NOT_IMPLEMENTED; if (aCID.equals(CLASS_ID)) return gFactory; throw Components.results.NS_ERROR_NO_INTERFACE; }, canUnload: function(aCompMgr) { return true; } }; var gFactory = { createInstance: function (aOuter, aIID) { if (aOuter != null) throw Components.results.NS_ERROR_NO_AGGREGATION; return (new ffDisk()).QueryInterface(aIID); } }; function NSGetModule(aCompMgr, aFileSpec) { return gModule; }